// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CommunityToolkit.Mvvm.SourceGenerators.UnitTests;

partial class Test_SourceGeneratorsCodegen
{
    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_WithNoModifiers_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                partial int Number { get; set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    partial int Number
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    // See https://github.com/CommunityToolkit/dotnet/issues/969
    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_RequiredProperty_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                public required partial int Number { get; private set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public required partial int Number
                    {
                        get => field;
                        private set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    // See https://github.com/CommunityToolkit/dotnet/issues/1013
    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_NewProperty_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;

            partial class BaseViewModel : ObservableObject
            {
                public int Number { get; private set; }
            }
            
            partial class MyViewModel : BaseViewModel
            {
                [ObservableProperty]
                public new partial int Number { get; private set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public new partial int Number
                    {
                        get => field;
                        private set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_VirtualProperty_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                public virtual partial int Number { get; private set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public virtual partial int Number
                    {
                        get => field;
                        private set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    [DataRow("override")]
    [DataRow("sealed override")]
    public void ObservablePropertyWithValueType_OnPartialProperty_OverrideProperty_WorksCorrectly(string modifiers)
    {
        string source = $$"""
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;

            partial class BaseViewModel : ObservableObject
            {
                public virtual partial int Number { get; private set; }
            }
            
            partial class MyViewModel : BaseViewModel
            {
                [ObservableProperty]
                public {{modifiers}} partial int Number { get; private set; }
            }
            """;

        string result = $$"""
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public {{modifiers}} partial int Number
                    {
                        get => field;
                        private set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_WithExplicitModifiers_WorksCorrectly1()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                public partial int Number { get; private set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial int Number
                    {
                        get => field;
                        private set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_WithExplicitModifiers_WorksCorrectly2()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                internal partial int Number { private get; set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    internal partial int Number
                    {
                        private get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<int>.Default.Equals(field, value))
                            {
                                OnNumberChanging(value);
                                OnNumberChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Number);
                                field = value;
                                OnNumberChanged(value);
                                OnNumberChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Number);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanging(int oldValue, int newValue);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int value);
                    /// <summary>Executes the logic for when <see cref="Number"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Number"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNumberChanged(int oldValue, int newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservablePropertyWithValueType_OnPartialProperty_WithExplicitModifiers_WorksCorrectly3()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp
            {
                public partial class MyViewModel : ObservableObject
                {
                    [ObservableProperty]
                    protected internal partial string Name { get; private protected set; }
                }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    protected internal partial string Name
                    {
                        get => field;
                        private protected set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

[TestMethod]
    public void ObservablePropertyWithReferenceType_NotNullable_OnPartialProperty_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            #nullable enable

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                public partial string Name { get; set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservablePropertyWithReferenceType_Nullable_OnPartialProperty_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            #nullable enable

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                public partial string? Name { get; set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string? Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string?>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string? value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string? oldValue, string? newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string? value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string? oldValue, string? newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservableProperty_OnPartialProperty_AlsoNotifyPropertyChange_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableObject
            {
                [ObservableProperty]
                [NotifyPropertyChangedFor(nameof(FullName))]
                public partial string Name { get; set; }

                public string FullName => "";
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.FullName);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.FullName);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservableProperty_OnPartialProperty_AlsoNotifyCanExecuteChange_WorksCorrectly()
    {
        string source = """
            using CommunityToolkit.Mvvm.ComponentModel;
            using CommunityToolkit.Mvvm.Input;

            namespace MyApp;
            
            partial class MyViewModel : ObservableRecipient
            {
                [ObservableProperty]
                [NotifyCanExecuteChangedFor(nameof(TestCommand))]
                public partial string Name { get; set; }

                public IRelayCommand TestCommand => null;
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                                TestCommand.NotifyCanExecuteChanged();
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservableProperty_OnPartialProperty_AlsoNotifyRecipients_WorksCorrectly()
    {
        string source = """
            using System.Windows.Input;
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableRecipient
            {
                [ObservableProperty]
                [NotifyPropertyChangedRecipients]
                public partial string Name { get; set; }
            }
            """;

        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                string __oldValue = field;
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                                Broadcast(__oldValue, value, "Name");
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }

    [TestMethod]
    public void ObservableProperty_OnPartialProperty_AlsoNotifyDataErrorInfo_WorksCorrectly()
    {
        string source = """
            using System.ComponentModel.DataAnnotations;
            using System.Windows.Input;
            using CommunityToolkit.Mvvm.ComponentModel;

            namespace MyApp;
            
            partial class MyViewModel : ObservableValidator
            {
                [ObservableProperty]
                [NotifyDataErrorInfo]
                [Required]
                public partial string Name { get; set; }
            }
            """;

#if NET6_0_OR_GREATER
        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        [global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("The type of the current instance cannot be statically discovered.")]
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                ValidateProperty(value, "Name");
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;
#else
        string result = """
            // <auto-generated/>
            #pragma warning disable
            #nullable enable
            namespace MyApp
            {
                /// <inheritdoc/>
                partial class MyViewModel
                {
                    /// <inheritdoc/>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
                    public partial string Name
                    {
                        get => field;
                        set
                        {
                            if (!global::System.Collections.Generic.EqualityComparer<string>.Default.Equals(field, value))
                            {
                                OnNameChanging(value);
                                OnNameChanging(default, value);
                                OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.Name);
                                field = value;
                                ValidateProperty(value, "Name");
                                OnNameChanged(value);
                                OnNameChanged(default, value);
                                OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                            }
                        }
                    }

                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="value">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
                    /// <param name="oldValue">The previous property value that is being replaced.</param>
                    /// <param name="newValue">The new property value being set.</param>
                    /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanging(string oldValue, string newValue);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="value">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string value);
                    /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
                    /// <param name="oldValue">The previous property value that was replaced.</param>
                    /// <param name="newValue">The new property value that was set.</param>
                    /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
                    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", <ASSEMBLY_VERSION>)]
                    partial void OnNameChanged(string oldValue, string newValue);
                }
            }
            """;
#endif

        VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, LanguageVersion.Preview, ("MyApp.MyViewModel.g.cs", result));
    }
}
